using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace ECommerce.Web.HtmlHelpers
{
    public static class HtmlElementIdentityHelper
    {
        public static string IdFor<T, TProperty>(Expression<Func<T, TProperty>> propertySelector)
        {
            string collectionPropertyFormat = "{0}_{1}_";

            IEnumerable<string> propertyChain = GetPropertyChain(propertySelector.Body, collectionPropertyFormat);

            return String.Join("_", propertyChain.ToArray());
        }

        public static string NameFor<T, TProperty>(Expression<Func<T, TProperty>> propertySelector)
        {
            string collectionPropertyFormat = "{0}[{1}]";

            IEnumerable<string> propertyChain = GetPropertyChain(propertySelector.Body, collectionPropertyFormat);

            return String.Join(".", propertyChain.ToArray());
        }

        private static IEnumerable<string> GetPropertyChain(Expression rootExpression, string collectionPropertyFormat)
        {
            IList<string> propertyChain = new List<string>();

            var stack = new Stack<Expression>();

            stack.Push(rootExpression);

            while (stack.Count > 0)
            {
                Expression current = stack.Pop();

                ParameterExpression parameterExpression = current as ParameterExpression;

                if (parameterExpression != null)
                {
                    propertyChain.Add(parameterExpression.Type.Name);
                }

                MemberExpression memberExpression = current as MemberExpression;

                if (memberExpression != null)
                {
                    propertyChain.Add(memberExpression.Member.Name);

                    stack.Push(memberExpression.Expression);
                }

                MethodCallExpression methodCallExpression = current as MethodCallExpression;

                if (methodCallExpression != null)
                {
                    MemberExpression collectionMemberExpression = methodCallExpression.Object as MemberExpression;

                    if (collectionMemberExpression != null)
                    {
                        string collectionProperyName = collectionMemberExpression.Member.Name;
                        object collectionIndex = GetCollectionIndex(methodCallExpression);

                        propertyChain.Add(String.Format(collectionPropertyFormat, collectionProperyName, collectionIndex));

                        stack.Push(collectionMemberExpression.Expression);
                    }
                }
            }

            return propertyChain.Reverse();
        }

        private static object GetCollectionIndex(MethodCallExpression methodCallExpression)
        {
            MemberExpression memberExpression = methodCallExpression.Arguments[0] as MemberExpression;

            if (memberExpression != null)
            {
                return Expression.Lambda(memberExpression).Compile().DynamicInvoke();
            }

            return ((ConstantExpression)methodCallExpression.Arguments[0]).Value;
        }
    }
}